using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Text;

namespace TmxLib
{
    public class NsiProjectBuilder: Component
    {
        public class Result
        {
            public readonly string AppName;
            public readonly string AppBuild;
            public readonly byte[] ExecutableImage;
            public readonly string OutputLog;
            public readonly string ErrorLog;


            public Result(string appName, string appBuild, byte[] executableImage, string outputLog, string errorLog)
            {
                AppName = appName;
                AppBuild = appBuild;
                ExecutableImage = executableImage;
                OutputLog = outputLog;
                ErrorLog = errorLog;
            }
        }

        private string _TmxEditorFolder;
        private string _tmxFullName;

        private string _workingFolder;

        public NsiProjectBuilder(string tmxEditorFolder, string tmxFullName)
        {
            _TmxEditorFolder = tmxEditorFolder;
            _tmxFullName = tmxFullName;
        }

        public Result Build(string appName, string appBuild)
        {
            _workingFolder =
                Path.Combine(
                    Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                    Guid.NewGuid().ToString("N"));

            _workingFolder = new DirectoryInfo(_workingFolder).FullName;
            try
            {
                Directory.CreateDirectory(_workingFolder);
            }
            catch
            {
            }

            string tmxTarget = Path.Combine(_workingFolder, appName + ".tmx");
            File.Copy(_tmxFullName, tmxTarget);

            using(Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(typeof (NsiProjectBuilder), "template.nsi"))
            {
                if (s == null)
                    throw new Exception("Embedded nsi template 'template.nsi' not found");

                using(StreamReader reader = new StreamReader(s))
                {
                    string template = reader.ReadToEnd();
                    string appNameWithBuild = appName +
                                              (appBuild != null && appBuild.Trim().Length > 0
                                                   ? (", " + appBuild.Trim())
                                                   : string.Empty);

                    string tmxEditorFolder = new DirectoryInfo(this._TmxEditorFolder).FullName;
                    string nsi = template
                        .Replace("<AppName>", appName)
                        .Replace("<Temp>", _workingFolder)
                        .Replace("<TmxEditor>", tmxEditorFolder)
                        .Replace("<AppNameWithBuild>", appNameWithBuild);

                    string nsiFile = Path.Combine(_workingFolder, appName + ".nsi");
                    using(FileStream fs = new FileStream(nsiFile, FileMode.Create, FileAccess.Write, FileShare.Read))
                    using(StreamWriter writer = new StreamWriter(fs, Encoding.Default))
                    {
                        writer.Write(nsi);
                    }

                    NsiExecBase nsiExec = NsiExecBase.GetInstance();
                    nsiExec.Exec(nsiFile);

                    string exeName = Path.Combine(_workingFolder, appName + ".exe");
                    using(FileStream fs = new FileStream(exeName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        byte[] exeImage = new byte[fs.Length];
                        fs.Read(exeImage, 0, exeImage.Length);

                        Result result = new Result(appName, appBuild, exeImage, null, null);
                        return result;
                    }
                }
            }
        }


        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);

            if (disposing)
            {
                if (_workingFolder != null)
                {
                    try
                    {
                        string f = _workingFolder;
                        _workingFolder = null;
                        Directory.Delete(f, true);
                    }
                    catch
                    {
                    }
                }
            }
        }
    }
}
